import java.util.ArrayList;

/**
 * @author Huhao
 * &#064;date  2024/10/02
 */

public class Lexical {
    private int i = 0;
    private int j = 0;
    public static int row = 1;
    private String token = "";
    private String analyzeResult = "";
    public static int errorsCount = 0;
    public static String errorDetailInfo = "";

    private String[] reservedWords = {
            "auto", "double", "int", "struct", "break", "else", "long", "switch", "case", "enum",
            "register", "typedef", "char", "extern", "return", "union", "const", "float", "short", "unsigned",
            "continue", "for", "signed", "void", "default", "goto", "sizeof", "volatile", "do", "if",
            "while", "static"
    };

    private String[] operators = {
            "+", "-", "*", "/", "%", ">", "<", ">=", "<=", "==",
            "-=", "+=", "*=", "/=", "!=", "=", "%=", "&", "&&", "|",
            "||", "!", "++", "--", "~", "<<", ">>", "?:"
    };

    private String[] bounds = {
            "{", "}", "[", "]", ";", ",", "(", ")", "\"", "'"
    };

    public String Scanner(String sourceFile) {
        if (sourceFile.length() == 0) {
            return "";
        }
        try {
            while (i < sourceFile.length()) {
                char ch = sourceFile.charAt(i);
                if (ch == ' ' || ch == '\t' || ch == '\r') {
                    i++;
                } else if (ch == '\n') {
                    row++;
                    i++;
                } else if (isLetter(ch) || isUnderline(ch)) {
                    token += ch;
                    idOrKeywordsRecog(sourceFile);
                    j = 0;
                    while (j < reservedWords.length && !token.equals(reservedWords[j])) {
                        j++;
                    }
                    if (j >= reservedWords.length) {
                        analyzeResult += row + "\t" + token + "\t标识符\t  合法\t\t89\r\n";
                    } else {
                        analyzeResult += row + "\t" + reservedWords[j] + "\t保留字\t  合法\t\t" + j + "\r\n";
                    }
                    token = "";
                } else if (isDigit(ch)) {
                    token += ch;
                    digitRecog(sourceFile);
                    analyzeNumber();
                    token = "";
                } else if (isBound(ch)) {
                    token = String.valueOf(ch);
                    j = 0;
                    while (j < bounds.length && !token.equals(bounds[j])) {
                        j++;
                    }
                    analyzeResult += row + "   \t" + token + "\t界符\t  合法\t\t" + (j + reservedWords.length + operators.length) + "\r\n";
                    token = "";
                    i++;
                } else if (isOperator(ch)) {
                    operatorRecog(sourceFile);
                    analyzeResult += row + "\t" + token + "\t运算符\t  合法\t\t" + (j + reservedWords.length) + "\r\n";
                    token = "";
                } else {
                    error(-3, String.valueOf(ch));
                    analyzeResult += row + "\t" + ch + "\t怪字符\t  非法\t\t-3\t←（错误行）\r\n";
                    i++;
                }
            }
        } catch (Exception e) {
            // Handle exception
        }
        return analyzeResult;
    }

    public boolean isLetter(char ch) {
        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
    }

    public boolean isDigit(char ch) {
        return ch >= '0' && ch <= '9';
    }

    public boolean isUnderline(char ch) {
        return ch == '_';
    }

    public boolean isBound(char ch) {
        for (String bound : bounds) {
            if (ch == bound.charAt(0)) {
                return true;
            }
        }
        return false;
    }

    public boolean isOperator(char ch) {
        for (String operator : operators) {
            if (ch == operator.charAt(0)) {
                return true;
            }
        }
        return false;
    }

    private void operatorRecog(String str) {
        token += str.charAt(i);
        i++;
        token += str.charAt(i);
        for (j = 0; j < operators.length; j++) {
            if (token.equals(operators[j])) {
                i++;
                break;
            }
        }
        if (j >= operators.length) {
            token = String.valueOf(str.charAt(i - 1));
        }
    }

    public void idOrKeywordsRecog(String str) {
        i++;
        while (isLetter(str.charAt(i)) || isDigit(str.charAt(i)) || isUnderline(str.charAt(i))) {
            token += str.charAt(i);
            i++;
        }
    }

    public void digitRecog(String str) {
        i++;
        while (i < str.length() && (str.charAt(i) == '.' || isDigit(str.charAt(i)) || isLetter(str.charAt(i)))) {
            token += str.charAt(i);
            i++;
        }
    }

    public void analyzeNumber() {
        boolean hasLetter = false;
        int dotCount = 0;
        for (int k = 0; k < token.length(); k++) {
            if (isLetter(token.charAt(k))) {
                hasLetter = true;
            }
            if (token.charAt(k) == '.') {
                dotCount++;
            }
        }
        if (hasLetter) {
            analyzeResult += row + "\t" + token + "\t标识符\t  非法\t\t-1\t←（错误行）\r\n";
            error(-1, token);
        } else if (dotCount <= 1) {
            analyzeResult += row + "\t" + token + "\t常量\t  合法\t\t90\r\n";
        } else {
            analyzeResult += row + "\t" + token + "\t常量\t  非法\t\t-2\t←（错误行）\r\n";
            error(-2, token);
        }
    }

    public void error(int k, String refers) {
        switch (k) {
            case -1:
                errorDetailInfo += row + "行\t " + refers + "\t\t   标识符命名错误\r\n";
                errorsCount++;
                break;
            case -2:
                errorDetailInfo += row + "行\t " + refers + "\t   常数错误\r\n";
                errorsCount++;
                break;
            case -3:
                errorDetailInfo += row + "行\t " + refers + "\t\t   非法字符\r\n";
                errorsCount++;
                break;
        }
    }


}
